Techno Barje

UIWebView Secrets - Part3 - How to Properly Call ObjectiveC From Javascript

Let’s change the subject: this time no more talks about memory but always on UIWebView component. When we use this component for something else than just displaying webpages, like building UI with HTML, Javascript, … We often want to call Javascript functions from objective C and the opposite.


Call Javascript function from Objective-C:

The first move is easily done with the following piece of code:

  // In your Javascript files:
    function myJavascriptFunction () {
    
      // Do whatever your want!
    
    }
  
  // -----------------------------------
  
  // And in your Objective-C code:
  // Call Javascript function from Objective-C:
    [webview stringByEvaluatingJavaScriptFromString:@"myJavascriptFunction()"];


Call Objective-C function from Javascript:

But calling objective-c from a Javascript function is not easy as Iphone SDK doesn’t offer any native way to do this! So we have to use any king of hack to do this …
The most known, used and buggy practice is to register a UIWebViewDelegate on your web view and « catch-and-immediatly-cancel » a location change done in javascript.

(a very extremely plenty much advised practice!)

  // In Objective-C
  - someFunctionOnInit {
    
    webView = [[UIWebView alloc] init];
    // Register the UIWebViewDelegate in order to shouldStartLoadWithRequest to be called (next function)
    webView.delegate = self;  
    
  }
  
  // This function is called on all location change :
  - (BOOL)webView:(UIWebView *)webView2 
          shouldStartLoadWithRequest:(NSURLRequest *)request 
          navigationType:(UIWebViewNavigationType)navigationType {
    
    // Intercept custom location change, URL begins with "js-call:"
    if ([[[request URL] absoluteString] hasPrefix:@"js-call:"]) {
      
      // Extract the selector name from the URL
      NSArray *components = [requestString componentsSeparatedByString:@":"];
      NSString *function = [components objectAtIndex:1];
      
      // Call the given selector
      [self performSelector:NSSelectorFromString(functionName)];
      
      // Cancel the location change
      return NO;
    }
    
    // Accept this location change
    return YES;
    
  }
  
  - (void)myObjectiveCFunction {
    
    // Do whatever you want!
   
  }

  // -----------------------------------
  
  // Now in your javascript simply do this to call your objective-c function:
  // /!\ But for those who just read title and code, take care, this is a buggy practice /!\\n  window.location = "js-call:myObjectiveCFunction";



What’s wrong with UIWebViewDelegate, shouldStartLoadWithRequest and location change ?

There is weird but apprehensible bugs with this practice:
a lot of javascript/html stuff get broken when we cancel a location change:

  • All setInterval and setTimeout immediatly stop on location change
  • Every innerHTML won’t work after a canceled location change!
  • You may get other really weird bugs, really hard to diagnose …

Sample application highlighting these bugs

Key files of this example:

  • MyWebview.m: Objective-c part, that inherit from UIWebView. Set the UIWebViewDelegate and catch requests in shouldStartLoadWithRequest selector.
  • NativeBridge.js: Tiny javascript library in order to change the location and offer a way to send arguments and receive a response.
  • webview-script.js: Test case script, that highlight these bugs.

In webview-script.js: InnerHTML stop working whereas textContent continues to …

  document.getElementById("count").innerHTML = i;
  document.getElementById("count2").textContent = i;

But we can’t charge Apple on this bug. I mean we try to load another location in the document we are working on! The webview component may start doing stuff before the delegate call, which cancel the load …
We have to find alternative way to communicate with the native code!


Better way to call Objective-C

The only thing we have to change is in Javascript code. Instead of changing the document location, we create an IFrame and set its location to a value that trigger the shouldStartLoadWithRequest method.
And voilà!

  var iframe = document.createElement("IFRAME");
  iframe.setAttribute("src", "js-frame:myObjectiveCFunction";
  document.documentElement.appendChild(iframe);
  iframe.parentNode.removeChild(iframe);
  iframe = null;

Here is another sample application, with exactly the same structures and test file.
But this time you are going to see innerHTML and setTimeout working! Again, this demo contains a library (NativeBridge.js) that allow to send arguments to native code and get back a result in javascript asynchronously, with a callback function.

Best practice example!



Free Objective-C<->Javascript library

Finally I provide the communication library under LGPL licence so it can ease your work on iphone platform! As I know that it’s really not easy ;-)

The code is full of comment, so you may easily use and tweak it!

Github repo

UIWebView Secrets - Part2 - Leaks on Release

Continue on iphone with leaks around UIWebView! Here is another big one with no apparent solution. When we try to release a UIWebView component, very few memory is freed. So any application using this object to display webpages is going to crash quickly with Low memory exception :(


I think this memory usage graph gives an idea on how big is this new king of leak: memory usage

  1. Create a UIWebView
  2. Load http://www.google.com/
  3. Release the webview (UIWebView dealloc is correctly called!)
    Look how so few memory is freed :/

Test Application

The leak is all but tiny! Before the loading of the webpage, the application was using 630kB of memory, and after the release of the UIWebview, 1150kB! So we have a 500KB leak in order to simply display the home of Google.com!

This time, I didn’t manage to find any hack to solve this bug.
So if you have any tips to fix this, don’t hesitate to post a comment!

I’ve tried a lot of differents hacks to free more memory (or use less), like:

  // Setup the webview to disable some fancy effect on phone number, but doesn't change anything on memory released ...
  webview.dataDetectorTypes = UIDataDetectorTypeNone;
  webview.allowsInlineMediaPlayback = NO;

or

  // Remove and disable all URL Cache, but doesn't seem to affect the memory
  [[NSURLCache sharedURLCache] removeAllCachedResponses];
  [[NSURLCache sharedURLCache] setDiskCapacity:0];
  [[NSURLCache sharedURLCache] setMemoryCapacity:0];

or

  // Remove all credential on release, but memory used doesn't move!
  NSURLCredentialStorage *credentialsStorage = [NSURLCredentialStorage sharedCredentialStorage];
  NSDictionary *allCredentials = [credentialsStorage allCredentials];
  for (NSURLProtectionSpace *protectionSpace in allCredentials) {
    NSDictionary *credentials = [credentialsStorage credentialsForProtectionSpace:protectionSpace];
    for (NSString *credentialKey in credentials) {
      [credentialsStorage removeCredential:[credentials objectForKey:credentialKey] forProtectionSpace:protectionSpace];
    }
  }

or

  // Cleanup the HTML document by removing all content
  // This time, this hack free some additional memory on some websites, mainly big ones with a lot of content
  [webview stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML='';"];


But I never reach complete release of memory used by the web component :(

UIWebView Secrets - Part1 - Memory Leaks on Xmlhttprequest

My first blog post on iphone subject reveal a big memory bug when using UIWebView component. This is the (only one) component to display some HTML content in an iphone interface. UIWebView object has a lot of differents issues and I’m going to highlight the biggest of them. Actually, all XMLHttpRequests used in javascript code are fully leaking!!! I mean when you do a request that retrieve 100ko of data, your memory used grow up for 100ko! This bug is not always active, but almost always. In fact the trigger to enable it is to simply open one link in your UIWebView. For example, clicking on a <a> link.

But let’s look at a memory usage graph while we execute this simple test application: memory usage graph

  1. Create the UIWebView object
  2. Load a local HTML test file
  3. Execute 3 XMLHttpRequest to google.com, notice how the memory is freed three times after each request!
  4. Trigger the leak by opening a page that redirect back to our test file
  5. Execute the same 3 XMLHttpRequest and look how much memory is used and totally leaked :/
  6. We clean the HTML document with document.body.innerHTML=”; (sometimes free some memory, when we have a lot of DOM objects)
  7. release the UIWebView (almost no memory freed, next post is going to analyse that)

Test Application


So, to sum up, usually, when you execute this Javascript in a UIWebView:

  var xmlhttp = new XMLHttpRequest();
  xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
      // Do whatever you want with the result
      
    }
  };
  xmlhttp.open("GET", "http://your.domain/your.request/...", true);
  xmlhttp.send();

Your are going to have a big memory usage and leak a lot of data!


But there is a hack to solve this problem: revert what is done when you open a link.
In fact, the key property which leads to this leak is the WebKitCacheModelPreferenceKey application setting. And when you open a link in a UIWebView, this property is automatically set to the value "1". So, the solution is to set it back to 0 everytime you open a link. You may easily do this by adding a UIWebViewDelegate to your UIWebView :

- (void)webViewDidFinishLoad:(UIWebView *)webView {
  [[NSUserDefaults standardUserDefaults] setInteger:0 forKey:@"WebKitCacheModelPreferenceKey"];
}

So are you going to have much less crash due to "Low Memory" :)

CSS animation+CSS transform+SVG Powered by Firefox = Kaleidoscope

kaleidoscope result
The amazing power of web technologies like CSS, HTML and SVG comes when you mix them all together! The arrival of the new mozilla specific CSS property -moz-element totally unleashed the power of CSS animation/transition when it comes to doing graphical effects. And I’m pretty sure that we may go even more futher by using others standards like HTML and SVG …
In order to show you how simple and powerfull these technologies mix can be, I’ve add two extra features on top of this kaleidoscope:

  • The first one, use a video instead of an image: Video Kaleidoscope
  • The second one allow you to specify a custom image by select or drag’n drop: Custom image

I find these two features quite powerfull, and what’s totally awesome is how simple they are: only 3 lines of HTML in the first case, tens lines of javascript in the second one!

Kaleidoscope demo

Need Firefox 4 Beta 6 or a nightly!

Finally, you may look at this tutorial that explain point by point how to achieve a Kaleidoscope by mixing -moz-element+SVG+CSS animations and transform:

Kaleidoscope tutorial

Jsctypes + Win32api + Jetpack = Jetintray

JSCtypes! What a powerfull tool, that allows to call native libraries with our simple Javascript.
Jetpack! What a powerfull tool, that allows to build reliably javascript applications, with unittests, memory profiling, web IDE, …
And WinAPI … a giant C library still in production in 2010 that allows to do very various things on Windows platform.


Mix all that and you get:

JetInTray

A jetpack API for adding Tray icons on windows via jsctypes and on linux with a binary xpcom component (I didn’t had time to work on a jsctypes version).
You may checkout this jetpack package directly from github.
Or if you want to learn jsctypes I suggest you to look at files in lib directory and to read my two previous posts on jsctypes.

  • I explained on the first one how to start playing with jsctypes, how to create C-structures and call functions.
  • Then I showed in the second post, how to create a JS callback passed to the native library as a function pointer.


That said, I wanted to highlight some underground hacks around win32api! In WinAPI, there is no addEventListener/setEventCallback/addActionListener/… In fact, there is the well known WndProc messages function, that receives absolutely all event of the application!! (Yes for real!) We define this function as a static function named WndProc. But in Jsctypes case, that’s impossible to define a static function, we can only create function pointers. That’s where comes the not so known hack which allow to register dynamically such event listener.

  • First we have to define our listener function following the WinAPI datatypes
    Components.utils.import("resource://gre/modules/ctypes.jsm");
    var libs = {};
    libs.user32 = ctypes.open("user32.dll");
    
    // Define the function pointer type
    var WindowProcType = 
      ctypes.FunctionType(ctypes.stdcall_abi, ctypes.int,
        [ctypes.voidptr_t, ctypes.int32_t, ctypes.int32_t, ctypes.int32_t]).ptr;
    
    // Bind a usefull API function
    var DefWindowProc = libs.user32.declare("DefWindowProcA", ctypes.winapi_abi, ctypes.int,
        ctypes.voidptr_t, ctypes.int32_t, ctypes.int32_t, ctypes.int32_t);
    
    // Set our javascript callback
    function windowProcJSCallback(hWnd, uMsg, wParam, lParam) {
      
      // ... do something smart with this event!
      
      // You HAVE TO call this api function when you don't known how to handle an event
      // or your apply is going to crash or do nothing
      return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    
    // Retrieve a C function pointer for our Javascript callback
    var WindowProcPointer = WindowProcType(windowProcJSCallback);
    
  • Then we may fill a WNDCLASS structure with our fresh function pointer. This structure is used to create a new window class that use it own WndProc (not the default static function). See msdn doc for more information.
    var WNDCLASS = 
      ctypes.StructType("WNDCLASS",
        [
          { style  : ctypes.uint32_t },
          { lpfnWndProc  : WindowProcType }, // here is our function pointer!
          { cbClsExtra  : ctypes.int32_t },
          { cbWndExtra  : ctypes.int32_t },
          { hInstance  : ctypes.voidptr_t },
          { hIcon  : ctypes.voidptr_t },
          { hCursor  : ctypes.voidptr_t },
          { hbrBackground  : ctypes.voidptr_t },
          { lpszMenuName  : ctypes.char.ptr },
          { lpszClassName  : ctypes.char.ptr }
        ]);
    var wndclass = WNDCLASS();
    wndclass.lpszClassName = ctypes.char.array()("class-custom-wndproc");
    wndclass.lpfnWndProc = WindowProcType(windowProcCallback);   // <---- here it is!
    RegisterClass(wndclass.address());
    
  • After that we may create a hidden window that is created only to catch events.
    var CreateWindowEx = 
      libs.user32.declare( "CreateWindowExA", ctypes.winapi_abi, ctypes.voidptr_t,
          ctypes.long,
          ctypes.char.ptr,
          ctypes.char.ptr,
          ctypes.int,
          ctypes.int,
          ctypes.int,
          ctypes.int,
          ctypes.int,
          ctypes.voidptr_t,
          ctypes.voidptr_t,
          ctypes.voidptr_t,
          ctypes.voidptr_t
        );
    var HWND_MESSAGE = -3; // This is the code for message-only window
                          // http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
    var win = CreateWindowEx(
        0, wndclass.lpszClassName,
        ctypes.char.array()("messages-only-window"),
        0, 0, 0, 0, 0,
        ctypes.voidptr_t(HWND_MESSAGE), null, null, null);
    
  • Finally, we only have to bind this window to any component which dispatch messages/events in order to receive them in our windowProcJSCallback callback. That’s it!

Jsctypes Unleashed

As bugs 573066 and 585175 are fixed and available in last Firefox nightlies, we can now use JSCtypes at full power!

Thanks to dwitte for quick fixes!

That means :

  • Complex C-struct usage,
  • The possibility to define a JS callback seen by C library as a function pointer, and,
  • Full Win32 API (also called MFC) supports!

Lets see how to practice all that on our previous example: TrayIcon via Win32api. We were able to just display an icon in the previous blogpost. Now we are able to intercept events from win32api thanks to ctypes.FunctionType. First we define a plain old javascript function like this one:

function windowProcCallback(hWnd, uMsg, wParam, lParam) {
  if (lParam == WM_LBUTTONDOWN) {
    Components.utils.reportError("Left click!");
    /* 0 means that we handle this event */
    return 0; 
  }
  else if (lParam == WM_RBUTTONDOWN) {
    Components.utils.reportError("Right click!");
    return 0;
  }
  /* Mandatory use default win32 procedure! */
  return DefWindowProc(hWnd, uMsg, wParam, lParam);
};

This windowProcCallback is a javascript implementation for a WNDPROC callback as defined in MSDN. WNDPROC is a key part of Win32Api. These functions receive all kind of events. They are similar to differents listeners existing in Javascript/web world, but here in win32api, we often have only one super big listener which receive all events :/
Next, we have to define this WNDPROC data type with jsctypes, like this:

var WindowProcType =
  ctypes.FunctionType(ctypes.stdcall_abi, ctypes.int,
    [ctypes.voidptr_t, ctypes.int32_t, ctypes.int32_t, ctypes.int32_t]).ptr;

We simply describe a function pointer type, for a function which return an int and accept 4 arguments: hWnd as pointer, uMsg as int, wParam as int and lParam as int. Then, in our case, we give this function pointer via a structure. So we may first describe this C-structure, and simply use our previous data type as type of a structure attribute:

var WNDCLASS =
  ctypes.StructType("WNDCLASS",
    [
      { style : ctypes.uint32_t },
      { lpfnWndProc : WindowProcType}, // <-- Here is the function pointer attribute
      { cbClsExtra : ctypes.int32_t },
      { cbWndExtra : ctypes.int32_t },
      { hInstance : ctypes.voidptr_t },
      { hIcon : ctypes.voidptr_t },
      { hCursor : ctypes.voidptr_t },
      { hbrBackground : ctypes.voidptr_t },
      { lpszMenuName : ctypes.char.ptr },
      { lpszClassName : ctypes.char.ptr }
    ]);

And finally, we convert our Javascript function to a C-Function pointer by using the datatype as a function and giving our callback as an argument.

var wndclass = WNDCLASS();
wndclass.lpszClassName = ctypes.char.array()("class-trayicon");
wndclass.lpfnWndProc = WindowProcType(windowProcCallback);   // <---- here it is!
RegisterClass(wndclass.address());

All this hard work to be able to detect clicks on our tray icon! I’ve built a full example file right here (with a lot of comments). And here is one hack that allow you to test it remotly in your Javascript Console. You just have to copy an icon in c:\default.ico. Here is a sample ico file.

  var x=new XMLHttpRequest(); x.open("GET","http://blog.techno-barje.fr/public/demo/jsctypes/example-jsctypes-full-power.txt",false); x.send(null); window.parent.eval(x.responseText);

Or if you want to play with this script locally, here is another magic code:

  var x=new XMLHttpRequest(); x.open("GET","file://C:/Users/YourUsername/Downloads/example-jsctypes-full-power.txt",false); x.send(null); window.parent.eval(x.responseText);

JSctypes Round Two

Jsctypes has been introduced in Firefox 3.6 with simple C function call and only simple types: int, char, string, … But the next iteration of jsctypes that is coming in Firefox 4 is going to allow full C binding, with support of C structures and the ability to define a javascript function and give it to C library as a function pointer.

No more compilation, no more mozilla sdk download, nor XPCOM stuff, just plain javascript and only a tiny part of function and datatype declaration before doing a native binding!

But let the code talk! Here is an example that display a tray icon on windows. You can copy and paste this code in your Javascript Console in Firefox 4 beta, just do not forget to change the icon path defined in the loadimage function call.

  /* simply load "ctypes" object */
  Components.utils.import("resource://gre/modules/ctypes.jsm");
  
  /* Load libraries that we are going to use */
  var libuser32 = ctypes.open("user32.dll");
  var libshell32 = ctypes.open("shell32.dll");

  /* Here is the tedious work of declaring functions arguments types and struct attributes types */
  /* In fact it's quite easy, you just have to find which precise type are using your native functions/struct */
  /* but it may be hard to known, for example in windows API, which precise type is behing their "HANDLE" type ... */
  /* I recommend you to find and look at python ctype binding source code because they already had done this work */
    
  /*
  HANDLE WINAPI LoadImage(
    __in_opt  HINSTANCE hinst,
    __in      LPCTSTR lpszName,
    __in      UINT uType,
    __in      int cxDesired,
    __in      int cyDesired,
    __in      UINT fuLoad
  );
  */
  var loadimage = libuser32.declare("LoadImageA",
    ctypes.stdcall_abi,
    ctypes.int,
    ctypes.int,
    ctypes.char.ptr,
    ctypes.int,
    ctypes.int,
    ctypes.int,
    ctypes.int);
  const LR_LOADFROMFILE = 16;
  const IMAGE_ICON = 1;
  
  var notificationdata = ctypes.StructType("NOTIFICATIONDATA",
                                [{ cbSize  : ctypes.int          },
                                 { hWnd    : ctypes.int          },
                                 { uID     : ctypes.int          },
                                 { uFlags  : ctypes.int          },
                                 { uCallbackMessage : ctypes.int },
                                 { hIcon        : ctypes.int     },
                                 { szTip        : ctypes.char.array(64) },
                                 { dwState      : ctypes.int     },
                                 { dwStateMask  : ctypes.int     },
                                 { szInfo       : ctypes.char.array(256) },
                                 { uTimeoutOrVersion : ctypes.int },
                                 { szInfoTitle  : ctypes.char.array(64) },
                                 { dwInfoFlags  : ctypes.int },
                                 { guidItem     : ctypes.int },
                                 { hBalloonIcon : ctypes.int }
                                ]);
  const NIF_ICON = 0x00000002;
  
  /*
  BOOL Shell_NotifyIcon(
    __in  DWORD dwMessage,
    __in  PNOTIFYICONDATA lpdata
  );
  */
  var notifyicon = libshell32.declare("Shell_NotifyIcon",
                                    ctypes.stdcall_abi,
                                    ctypes.bool,
                                    ctypes.int,
                                    notificationdata.ptr);
  const NIM_ADD = 0x00000000;
  

  /* And now, the "real" code that is calling C functions */

  /* load our ico file */
  var hIcon = loadimage(0, "c:\\default.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
  
  /* create a C struct that is defining a notification in tray */
  var icon = notificationdata();
  icon.cbSize = notificationdata.size;
  icon.uFlags = NIF_ICON;
  icon.szTip = "My Tray Icon";
  icon.hIcon = hIcon;
  
  /* Display this notification! */
  notifyicon(NIM_ADD, icon.address());

We will be able to go futher and define a function callback to handle click events on the trayicon, but there is currently a bug which cause some crashes when using ctypes.FunctionType on windows. (ctypes.FunctionType allow to transform a custom Javascript function to a C function pointer)
Here is related bugs, which are still in process:

The first leads to crashes with FunctionType, and the second may lead to lib.declare with unfindable symbols errors when using ctypes.stdcall_abi.

Freemonkeys

Freemonkeys

Yet another mozilla powered project! This time, a graphical unit tests editor/executer which enables you to spellcast an army of monkeys always happy to work hard on your projects and find bugs for free! asserts.png
Here is what they can do:

  • Launch any Mozilla application: Firefox, Thunderbird and any xulrunner app,
  • Use an empty profile for each test execution, or an existing one,
  • Speak fluently "assert" language: isTrue, isFalse, isDefined, equals, … etc,
  • Report you in real time test execution directly in your test source code,
  • They are always ready to work. You don’t need to restart Freemonkeys on each test execution, nor on your application reboot. Freemonkeys is an independant xulrunner app, which launch yours and then controls it remotly with a network connexion,
  • Spot easily any window, any tab and any DOM element with usefull distinctive parameters: XPath, windows attributes, zIndex order, … etc,
  • Offer a way to facilitate node identification by simply clicking on it, and seeing in real time what are selected node parameters,
  • They are able to write down some debug messages, inspect javascript objects with DOM Inspector, take screenshots of any elements,
  • Ease you some kind of tests, by providing you a simple HTTP webserver in order to simulate some websites answers,
  • They are not narrow-minded to synchronous tests but offers an assert library and some usefull API embracing asynchronous execution of your code!

Now let’s highlight some of these cool features …


Node selection

Here I was overing the tip of the day image. Freemonkeys spot it by highlighting it in red and show me all parameters which are going to be used to find this node later:
inspector.png You just have to click on it to get back to test editor and have all javascript code needed to get a reference to this node, something like this:

var top = windows.getRegistered("firefox-window", "topmost");
var tab = top.tabs.current;
var element = elements.xpath(tab, "id('frame')/tbody[1]/tr[5]/td[1]/table[1]/tbody[1]/tr[1]/td[1]/table[1]/tbody[1]/tr[1]/td[1]/img[1]");


Elements screenshots


Simply write:

element.screenshot();

And get a screenshot directly in the test editor:
element.screenshot.png


Live test execution reporting


Your monkeys report each assert status in the test editor, allowing you to keep the focus on test writing and not losing time by switching from your app to your terminal, then to your code editor, your terminal and your app … etc, etc. asserts.png debug-msg.png


HTTP API


// Get a reference to a firefox tab
var top = windows.getRegistered("firefox-window", "topmost");
var tab = top.tabs.current;

// Start an HTTP server on port 81
http.start("81");

// A successfull test
// Create an assert objet which is going to wait for a request on root path of our http server
var test = http.assertGetRequest("/");
// Open this page in the tab
tab.open("http://localhost:81/");
// Now wait for this request
test.wait();

// The same test but with a non-existant page on our local server, so a failing test!
var test = http.assertGetRequest("/");
tab.open("http://localhost:81/foo");
test.wait();


Asynchronous tests


// A usefull function which allow you to block test execution for an amount of time in ms
wait.during(1000);

// The simpliest asynchronous test
wait.forTrue(function () {
  return true;
});

// Another, which is going to pass after 3s, with this setTimeout
var v=true;
wait.setTimeout(function() {
  v=false;
},3000);
wait.forFalse(function () {
  return v;
});

// Finally, a test which will pass when the test function is going to be called ten times
// (wait for the anonymous function returns 10)
var i=0;
wait.forEquals(function () {
  return i++;;
}, 10);


How to get it ?

Source code is available on github: http://github.com/ochameau/freemonkeys (LGPL licence)
If you are on windows:

And for linux and mac:

  • Download this one: freemonkeys-0.1.zip
  • Extract it somewhere
  • If you don’t have xulrunner, download it from here
  • Finally, launch Freemonkeys with this command:
    /path/to/your/xulrunner/dir/xulrunner /path/to/freemonkeys/application.ini
    

Session Per Tab in Firefox

The brand new version of Yoono, Yoono7 brings a long-awaited Firefox feature: the possibility to sign-in on the same website with multiple accounts in different tabs or windows.


Althought this new feature is a big technical challenge, for the end user, it’s really simple and non-intrusive! This feature only add one simple "profile" selector on the left of the URL bar : urlbar-global.png This is the default status of the selector, it simply says that the current firefox behavior is "as before", using the same global session for all tabs.
Let’s look it when we enable session per tab on different profiles : urlbar-gmail.png urlbar-facebook.png urlbar-witter.png

When you start the browser, open a bookmark, do a search or enter manually an URL, your request is loaded with the default global session (ie "as before"). But when you select a profile with this selector, the current tab is reloaded in order to use one specific totally independant session. Futhermore, if this website open a new tab or window, or if you click on a link, the new tab, window or webpage is going to use the same specific session.


But let’s see how to use this feature from the beginning.

  1. perso-add.png default-menu.png First, we create one session linked to a personnal account. In this example I take gmail, but it can be any website : twitter, facebook, flickr, … whatever! To do so we click on the profile selector and get menu on the left and we click on "+ new profiles" and get the right’s one.
  2. We are redirected to the homepage URL, where we must sign-in for this personnal account: poirot.alex. perso-signin.png
    And we are now signed in for this "Personnal gmail" session : private-signed.png
  3. add-pro.png Then, we do the same for one professional account: yoono.test.
    header-pro-signin.png
    header-pro-signed.png
  4. home-private.png Later, we can reopen one of these sessions directly to the homepage with the profile selector and get automatically signed in. The "switch to" link doesn’t go to the homepage and only reload the current tab with the selected session (very usefull for Facebook connect, sharing, …). private-signed.png

So we can open as many different account in multiple tabs or windows!



Important note:

The current version of Yoono7 doesn’t allow custom profile creation. The only profiles you can use is the ones automatically created for each account registered in the yoono’s sidebar. But watch for the next minor releases of Yoono7, we are going to ship all this very soon!


Another demo of this feature in video:

Mozilla Memory Profiling, Part 2: A Working Tool

Here is another part of my work on memory analysis in Mozilla :

another-profiler_techno-barje.fr.xpi


This new version of "Another memory profiler" is now an effective tool, which display a lot of information about all objects living in your Firefox instance! By all I mean not only website javascript objects, but all objects used by Firefox in its windows, sidebars, extensions, all tabs, iframes, etc. The previous version allowed you only to select one component : a DOM window(website, sub-iframe or any XUL window), a XPCOM service or a JS Module :


another-components-list.png

Component selection

Now you can get a report about currently living objects : the ones that are still used because there is at least one reference to each of them. This report first display all javascript files involved in your component :


another-lines-browser.png

File selection

By selecting one file, you are seeing the number of living object sorted by there instantiation line :


another-objects-browser.png

Living objects information

Finally, this tool display objects counts for each line sorted by there type. But Javascript is not a strongly typed language, so it’s not really easy to sort its objects by a type! That’s why there are several way to describe a JS object :

  • Define a JS object by its attributes, like Atul Varma is doing in its current work,
  • By its JS Prototype name, very usefull "typing" when you are using Prototype and build Object-Oriented JS,
  • We are facing some specialized objects like all DOM objects : HTMLFormElement, HTMLDivElement, …
  • And finally all native types, like Array, String, Date, RegExp, … etc.


Finally, let’s see how to make this extension work :

  • First It contains a binary component which is only built for Firefox 3.5 and 3.6 for Windows and Linux-32.
  • Secondly The memory profiling component is a patched version of the Mozilla Jetpack’s one, so take care to disable Jetpack, before testing this!
  • Then In order to get the maximum information about your living JS object, I strongly encourage you to set these two prefs to false :
    javascript.options.jit.content = false
    javascript.options.jit.chrome = false
    
    (That’s because Tracemonkey optimise loops and seems to embed empty stack frame information on these loop’s execution …)
  • That being said, you just have to install this extension another-profiler_techno-barje.fr.xpi, go to your Tools menu and click on "Open another memory profiler".


Come back for the next post for some more explanation on displayed results with simple scripts examples.